package cn.schoolwow.quickdao.module.database.dql.condition.flow.set;

import cn.schoolwow.quickdao.domain.QuickDAOConfig;
import cn.schoolwow.quickdao.domain.entity.Entity;
import cn.schoolwow.quickdao.domain.entity.Property;
import cn.schoolwow.quickdao.domain.provider.DatabaseProvider;
import cn.schoolwow.quickdao.module.database.dql.condition.domain.SQLFragmentEntry;
import cn.schoolwow.quickdao.module.database.dql.parent.domain.QueryContext;
import cn.schoolwow.quickdao.module.database.dql.subCondition.domain.SubQueryOption;
import cn.schoolwow.quickflow.domain.FlowContext;
import cn.schoolwow.quickflow.flow.BusinessFlow;

import java.util.List;

public class SetQueryFragmentFlow implements BusinessFlow {
    @Override
    public void executeBusinessFlow(FlowContext flowContext) throws Exception {
        flowContext.putTemporaryData("noAliasNameWhereBuilder", new StringBuilder());
        flowContext.putTemporaryData("whereBuilder", new StringBuilder());
        flowContext.putTemporaryData("groupByBuilder", new StringBuilder());
        flowContext.putTemporaryData("havingBuilder", new StringBuilder());
        flowContext.putTemporaryData("orderByBuilder", new StringBuilder());

        concatQuery(flowContext);
        concatSubQuery(flowContext);
        setQueryContextFragment(flowContext);
        setWhereAndHavingParameters(flowContext);
    }

    @Override
    public String name() {
        return "设置查询语句片段";
    }

    private void concatQuery(FlowContext flowContext){
        QuickDAOConfig quickDAOConfig = flowContext.checkInstanceData(QuickDAOConfig.class);
        QueryContext queryContext = (QueryContext) flowContext.checkData("queryContext");
        StringBuilder noAliasNameWhereBuilder = (StringBuilder) flowContext.checkData("noAliasNameWhereBuilder");
        StringBuilder whereBuilder = (StringBuilder) flowContext.checkData("whereBuilder");
        StringBuilder groupByBuilder = (StringBuilder) flowContext.checkData("groupByBuilder");
        StringBuilder havingBuilder = (StringBuilder) flowContext.checkData("havingBuilder");
        StringBuilder orderByBuilder = (StringBuilder) flowContext.checkData("orderByBuilder");
        boolean addTableAliasName = (boolean) flowContext.checkData("addTableAliasName");

        //拼接主表片段
        //where不带表别名子句
        concatFragment(queryContext.queryOption.queryTableOption.entity,
                queryContext.queryOption.queryFragmentOption.whereList,
                queryContext.queryOption.queryTableOption.tableAliasName,
                false,
                quickDAOConfig.databaseContext.databaseProvider,
                noAliasNameWhereBuilder);
        //where子句
        concatFragment(queryContext.queryOption.queryTableOption.entity,
                queryContext.queryOption.queryFragmentOption.whereList,
                queryContext.queryOption.queryTableOption.tableAliasName,
                addTableAliasName,
                quickDAOConfig.databaseContext.databaseProvider,
                whereBuilder);
        //groupBy子句
        concatFragment(queryContext.queryOption.queryTableOption.entity,
                queryContext.queryOption.queryFragmentOption.groupByList,
                queryContext.queryOption.queryTableOption.tableAliasName,
                addTableAliasName,
                quickDAOConfig.databaseContext.databaseProvider,
                groupByBuilder);
        //having子句
        concatFragment(queryContext.queryOption.queryTableOption.entity,
                queryContext.queryOption.queryFragmentOption.havingList,
                queryContext.queryOption.queryTableOption.tableAliasName,
                addTableAliasName,
                quickDAOConfig.databaseContext.databaseProvider,
                havingBuilder);
        //orderBy子句
        concatFragment(queryContext.queryOption.queryTableOption.entity,
                queryContext.queryOption.queryFragmentOption.orderByList,
                queryContext.queryOption.queryTableOption.tableAliasName,
                addTableAliasName,
                quickDAOConfig.databaseContext.databaseProvider,
                orderByBuilder);
    }

    private void concatSubQuery(FlowContext flowContext){
        QuickDAOConfig quickDAOConfig = flowContext.checkInstanceData(QuickDAOConfig.class);
        QueryContext queryContext = (QueryContext) flowContext.checkData("queryContext");
        StringBuilder noAliasNameWhereBuilder = (StringBuilder) flowContext.checkData("noAliasNameWhereBuilder");
        StringBuilder whereBuilder = (StringBuilder) flowContext.checkData("whereBuilder");
        StringBuilder groupByBuilder = (StringBuilder) flowContext.checkData("groupByBuilder");
        StringBuilder orderByBuilder = (StringBuilder) flowContext.checkData("orderByBuilder");
        boolean addTableAliasName = (boolean) flowContext.checkData("addTableAliasName");

        //拼接子表片段
        for(SubQueryOption subQueryOption:queryContext.queryOption.subQueryOptionList){
            if (null == subQueryOption.subQueryTableOption.tableAliasName) {
                subQueryOption.subQueryTableOption.tableAliasName = "t" + (queryContext.queryOption.queryTableOption.joinTableIndex++);
            }
            concatFragment(subQueryOption.subQueryTableOption.entity,
                    subQueryOption.subQueryFragmentOption.whereList,
                    subQueryOption.subQueryTableOption.tableAliasName,
                    false,
                    quickDAOConfig.databaseContext.databaseProvider,
                    noAliasNameWhereBuilder);
            concatFragment(subQueryOption.subQueryTableOption.entity,
                    subQueryOption.subQueryFragmentOption.whereList,
                    subQueryOption.subQueryTableOption.tableAliasName,
                    addTableAliasName,
                    quickDAOConfig.databaseContext.databaseProvider,
                    whereBuilder);
            concatFragment(subQueryOption.subQueryTableOption.entity,
                    subQueryOption.subQueryFragmentOption.groupByList,
                    subQueryOption.subQueryTableOption.tableAliasName,
                    addTableAliasName,
                    quickDAOConfig.databaseContext.databaseProvider,
                    groupByBuilder);
            concatFragment(subQueryOption.subQueryTableOption.entity,
                    subQueryOption.subQueryFragmentOption.orderByList,
                    subQueryOption.subQueryTableOption.tableAliasName,
                    addTableAliasName,
                    quickDAOConfig.databaseContext.databaseProvider,
                    orderByBuilder);
        }
    }

    private void setQueryContextFragment(FlowContext flowContext){
        QueryContext queryContext = (QueryContext) flowContext.checkData("queryContext");
        StringBuilder noAliasNameWhereBuilder = (StringBuilder) flowContext.checkData("noAliasNameWhereBuilder");
        StringBuilder whereBuilder = (StringBuilder) flowContext.checkData("whereBuilder");
        StringBuilder groupByBuilder = (StringBuilder) flowContext.checkData("groupByBuilder");
        StringBuilder havingBuilder = (StringBuilder) flowContext.checkData("havingBuilder");
        StringBuilder orderByBuilder = (StringBuilder) flowContext.checkData("orderByBuilder");

        if(noAliasNameWhereBuilder.length()>0){
            //前缀为" and "或者" or ",因此删除5个
            if(noAliasNameWhereBuilder.indexOf(" and ")==0){
                noAliasNameWhereBuilder.delete(0,5);
            }else if(noAliasNameWhereBuilder.indexOf(" or ")==0){
                noAliasNameWhereBuilder.delete(0,4);
            }
            noAliasNameWhereBuilder.insert(0, " where ");
            queryContext.noAliasNameWhere = noAliasNameWhereBuilder.toString();
        }
        if(whereBuilder.length()>0){
            //前缀为" and "或者" or ",因此删除5个
            if(whereBuilder.indexOf(" and ")==0){
                whereBuilder.delete(0,5);
            }else if(whereBuilder.indexOf(" or ")==0){
                whereBuilder.delete(0,4);
            }
            whereBuilder.insert(0, " where ");
            queryContext.where = whereBuilder.toString();
        }
        if(groupByBuilder.length()>0){
            //前缀为",",因此删除3个
            groupByBuilder.delete(0,3);
            groupByBuilder.insert(0, " group by ");
            queryContext.groupBy = groupByBuilder.toString();
        }
        if(havingBuilder.length()>0){
            //前缀为" and ",因此删除5个
            havingBuilder.delete(0,5);
            havingBuilder.insert(0, " having ");
            queryContext.having = havingBuilder.toString();
        }
        if(orderByBuilder.length()>0){
            //前缀为",",因此删除3个
            orderByBuilder.delete(0,3);
            orderByBuilder.insert(0, " order by ");
            queryContext.orderBy = orderByBuilder.toString();
        }
        if(!queryContext.queryOption.queryPagingOption.limit.isEmpty()){
            queryContext.limit = " " + queryContext.queryOption.queryPagingOption.limit;
        }
    }

    private void setWhereAndHavingParameters(FlowContext flowContext){
        QueryContext queryContext = (QueryContext) flowContext.checkData("queryContext");

        queryContext.whereParameters.addAll(queryContext.queryOption.queryFragmentOption.whereParameterList);
        queryContext.havingParameters.addAll(queryContext.queryOption.queryFragmentOption.havingParameterList);
    }

    private void concatFragment(Entity entity, List<SQLFragmentEntry> fieldFragmentEntryList, String tableAliasName, boolean addTableAliasName, DatabaseProvider databaseProvider, StringBuilder sqlBuilder){
        if(fieldFragmentEntryList.isEmpty()){
            return;
        }
        StringBuilder fragmentBuilder = new StringBuilder();
        for(SQLFragmentEntry fieldFragmentEntry: fieldFragmentEntryList){
            fragmentBuilder.append(" " + fieldFragmentEntry.concat + " ");

            if(null==fieldFragmentEntry.field||!fieldFragmentEntry.fragment.contains("{}")){
                fragmentBuilder.append(fieldFragmentEntry.fragment);
                continue;
            }
            if(null==entity){
                fragmentBuilder.append(fieldFragmentEntry.fragment.replace("{}", fieldFragmentEntry.field));
                continue;
            }
            Property property = entity.getPropertyByFieldNameOrColumnName(fieldFragmentEntry.field);
            if(null==property){
                fragmentBuilder.append(fieldFragmentEntry.fragment.replace("{}", fieldFragmentEntry.field));
            }else if(addTableAliasName){
                fragmentBuilder.append(fieldFragmentEntry.fragment.replace("{}", tableAliasName + "." + databaseProvider.escape(property.column)));
            }else{
                fragmentBuilder.append(fieldFragmentEntry.fragment.replace("{}", databaseProvider.escape(property.column)));
            }
        }
        sqlBuilder.append(fragmentBuilder.toString());
    }
}
